// -------------------------------------------------------------------------
// Copyright (c) 2000-2009 Ufinity. All Rights Reserved.
//
// This software is the confidential and proprietary information of
// Ufinity
//
// Original author: lxt
//
// -------------------------------------------------------------------------
// UFINITY MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
// THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE, OR NON-INFRINGEMENT. UFINITY SHALL NOT BE
// LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
// MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
//
// THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
// CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
// PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
// NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
// SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
// SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
// PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). UFINITY
// SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
// HIGH RISK ACTIVITIES.
// -------------------------------------------------------------------------

package com.ufinity.estimation.site.security;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.RegexUrlPathMatcher;
import org.springframework.security.web.util.UrlMatcher;

import com.cn.ufinity.common.log.Logger;
import com.cn.ufinity.common.log.LoggerFactory;
import com.ufinity.estimation.persistence.domain.Resource;
import com.ufinity.estimation.persistence.domain.User;
import com.ufinity.estimation.service.ResourceService;

/**
 * 
 * Description of the class
 * 
 * @author lxt
 * @version 1.0
 * @since 2010-6-8
 */
public class DefaultInvocationSecurityMetadataSource implements
        FilterInvocationSecurityMetadataSource, InitializingBean {
    private static Logger logger = LoggerFactory
    .getSystemLog(DefaultInvocationSecurityMetadataSource.class);

    
    private static UrlMatcher urlMatcher = new RegexUrlPathMatcher();

    private static Map<Object, Collection<ConfigAttribute>> resourcesMap = new HashMap<Object, Collection<ConfigAttribute>>();

    private static ResourceService resourceService;

    public DefaultInvocationSecurityMetadataSource() {

    }

    public void setResourceService(ResourceService resourceService) {
        DefaultInvocationSecurityMetadataSource.resourceService = resourceService;
    }

    private void loadResourceDefine() {
        reloadAllResourceRight();
    }
    
    public static void reloadAllResourceRight() {
        String method = "reloadAllResourceRight";
        List<Resource> resources = resourceService.findAll();
        logger.info(method, "reloading all need authorize urls");
        resourcesMap.clear();
        for (Resource resource : resources) {
            Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();
            for (User user : resource.getUsers()) {
                atts.add(new SecurityConfig(user.getUsername()));
            }
            
            logger.info(method, "resource[name=" + resource.getName() + "] [url=" + resource.getUrl()+ "]" + " authorize to " + atts);
            if (StringUtils.isNotEmpty(resource.getUrl())) {
                resourcesMap.put(urlMatcher.compile(resource.getUrl()), atts);
            } else {
                
            }
            
        }
    }

    // According to a URL, Find out permission configuration of this URL.
    public Collection<ConfigAttribute> getAttributes(Object object)
            throws IllegalArgumentException {
        String method = "getAttributes";
        // guess object is a URL.
        String url = ((FilterInvocation) object).getRequestUrl();
        Iterator<Object> ite = resourcesMap.keySet().iterator();
        logger.debug(method, "request [url=" + url + "]" );
        while (ite.hasNext()) {
            Object resURL = ite.next();
            if (urlMatcher.pathMatchesUrl(resURL, url)) {
                logger.debug(method, "request [url=" + url + "] need role " + resourcesMap.get(resURL));
                return resourcesMap.get(resURL);
            }
        }
        return null;
    }

    /**
     * {@inheritDoc}
     * 
     * @since 2010-6-8
     * @see org.springframework.security.access.SecurityMetadataSource#supports(java.lang.Class)
     */
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }

    /**
     * {@inheritDoc}
     * 
     * @since 2010-6-8
     * @see org.springframework.security.access.SecurityMetadataSource#getAllConfigAttributes()
     */
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        Set<ConfigAttribute> allAttributes = new HashSet<ConfigAttribute>();

        for (Map.Entry<Object, Collection<ConfigAttribute>> entry : resourcesMap
                .entrySet()) {
            allAttributes.addAll(entry.getValue());
        }

        return allAttributes;
    }

    public void afterPropertiesSet() throws Exception {
        loadResourceDefine();
    }
}
